﻿using System;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using Ext.Net;

namespace KamLib
{

    public abstract class EntitiesFormLogic<TFormControl, TFormData, TEntities>
        : FormLogic<TFormControl, TFormData>, IEntitiesContainer
        where TFormControl : WindowFormLogicControl
        where TFormData : class, new()
        where TEntities : ObjectContext, new()
    {
        public TEntities db;
        ObjectContext IEntitiesContainer.Entities { get { return db; } set { db = (TEntities)value; } }

        public override void Assign(ControlLogic src)
        {
            base.Assign(src);

            var sEntities = src as IEntitiesContainer;
            if (sEntities == null) return;
            var entities = sEntities.Entities as TEntities;
            if (entities != null) db = entities;
        }

        public override void Activate()
        {
            if (db == null)
                db = new TEntities();
        }

        public override void Dispose()
        {
            if (db == null) return;
            db.Dispose();
            db = null;
        }
    }


    public abstract class EntityFormLogic<TFormControl, TFormData, TEntities, TEntity>
        : EntitiesFormLogic<TFormControl, TFormData, TEntities>
        where TFormControl : WindowFormLogicControl
        where TFormData : class, new()
        where TEntities : ObjectContext, new()
        where TEntity : EntityObject, new()
    {
        public TEntity Entity;

        protected static System.Linq.Expressions.Expression<Func<TEntity, TFormData>> selectExpression;

        /// <summary>
        /// Выражение вида:
        /// a => new FormData { Field1 = a.Parent.Field1, ... }
        /// Используется в Select для полей, которые берутся из других Entities
        /// </summary>
        protected static System.Linq.Expressions.Expression<Func<TEntity, TFormData>> SelectInit;



        protected override TFormData Select()
        {
            var values = Select(SelectInit);
            SelectLocalDetails(values);
            return values;
        }

        protected TFormData Select(System.Linq.Expressions.Expression<Func<TEntity, TFormData>> init)
        {
            return Table().Filter(Key.ID).Select(ref selectExpression, init).FirstOrDefault();
        }

        protected override void SaveEntities()
        {
            var tbl = Table();

            Entity = Key.IsNew ? new TEntity() : tbl.Filter(Key.ID).FirstOrDefault();

            if (Entity == null)
                throw new Exception("The " + EntityDesc.Name + " with id = " + Key + " is not exist.");

            if (Key.MasterID != null) Key.MasterID.CopyTo(Values);
            PreSaveValues();
            AfterPreSaveValues();
            if (Key.MasterID != null) Entity.CopyFrom(Key.MasterID);
            Entity.CopyFrom(Values);

            if (Key.IsNew)
            {
                db.AddObject(TableName(), Entity);
            }

            SaveLocalChanges();
            db.SaveChanges();

            foreach (var keyfield in KeyFields)
            {
                try
                {
                    Key[keyfield] = typeof(TEntity).GetValue(Entity, keyfield, null);
                }
                catch (Exception ex)
                {
                    throw new Exception("Can't get KeyField '" + keyfield + "' from entity '" + typeof(TEntity).Name + "'. \r\n" + ex.FullMessage());
                }
            }
            Values = null;
        }

        public override void DeleteEntity()
        {
            var tbl = Table();
            var entity = tbl.Filter(Key.ID).FirstOrDefault();
            if (entity == null) return;
            tbl.DeleteObject(entity);
            db.SaveChanges();

            ReloadDependentStores();
        }


        public ObjectSet<TEntity> Table()
        {
            return db.Table<TEntity>();
        }
        public string TableName()
        {
            return db.TableProp<TEntity>().Name;
        }

    }


    public abstract class EntityFormLogic<TFormData, TEntities, TEntity>
        : EntityFormLogic<WindowFormLogicControl, TFormData, TEntities, TEntity>
        where TFormData : class, new()
        where TEntities : ObjectContext, new()
        where TEntity : EntityObject, new()
    {
    }

}